/**
 * 
 */
package tests;

import global.SystemDefs;
import heap.InvalidTupleSizeException;
import heap.InvalidTypeException;
import heap.Tuple;
import index.IndexException;
import iterator.JoinsException;
import iterator.LowMemException;
import iterator.PredEvalException;
import iterator.SortException;
import iterator.UnknowAttrType;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;

import code.query;
import code.FileStatistics;
import code.PCounter;

import diskmgr.rdfDB;

import btree.BT;
import btree.BTreeFile;
import btree.GetFileEntryException;
import btree.Interface3;
import btree.PinPageException;
import btree.RdbIndexType;
import bufmgr.PageNotReadException;


/**
 * @author smriti
 *
 */
public class runTest {
	
	private static Log log = Log.getInstance(runTest.class.getName());
	String dbname = "/tmp/dbtest";
	int num = 1000;
	int indexOption = 0;
	int orderOption = 0;
	BTreeFile file = null;
	public int counter = 0;
	public int fctr = -1;
	public Interface3 [] i3 = new Interface3 [10];
	public HashMap<String, Interface3> databases = new HashMap<String, Interface3>();
	public HashMap<String, Integer> counters = new HashMap<String, Integer>();
	public FileStatistics [] fS = new FileStatistics [10];
	
	


	private int menu() throws Exception {
		System.out.println("-------------------------- MENU ------------------");
		System.out.println("\n\n[0] Batch Insert");
		System.out.println("[1] Print the B+ Tree Structure");
		System.out.println("[2] Print the leaf nodes in the B+ Tree");
		System.out.println("\n[3] Query ");

		System.out.println("\n[4] Delete Triple(Format is subject, predicate, object)");

		System.out.println("\n[7] Report");
		System.out.println ("\n[8] Comparative analysis");
		
		System.out.println("\n[9] Join");

		System.out.println("\n[20]  Quit!");
		log.write ("Buffer Statistics:\n Number of unpinned buffers: "
				+ SystemDefs.JavabaseBM.getNumUnpinnedBuffers() +"\n");
		log.write ("Number of buffers that are used:"+SystemDefs.JavabaseBM.getNumBuffers() +"\n");

		System.out.print("Hi, make your choice :");
		return GetStuff.getIntChoice();
	}

	public void runAllTests() throws GetFileEntryException, PinPageException, Exception{
		int choice = 0;
		Integer ctr = 0;
		Interface3 i = new Interface3();
		i.superinit("/tmp/db", num, 5);

		while(choice != 20){
			try{
				choice = menu();
				int pagesAllocated = PCounter.getPagesAllocated();
				int pagesDeallocated = PCounter.getPagesDeallocated();
				int readCounter = PCounter.getreadCounter();
				int writeCounter = PCounter.getwriteCounter();
				int no_of_files = PCounter.get_no_of_files();
				switch(choice){
				case 0:										
					System.out.println("Please give the data filename ");
					String datafilename = GetStuff.getStrChoice();
					System.out.println("Please select the Index Option");
					System.out.println("1. Group1 - 6 indexes");
					indexOption = GetStuff.getIntChoice();
					System.out.println("Please choose a database name");
					String dbname = GetStuff.getStrChoice();
					if (databases.get(dbname) != null) {
						i = databases.get(dbname);
						ctr = counters.get(dbname);
					}
					else {
						i = new Interface3 ();
						fS [++fctr] = new FileStatistics();
						ctr++;
						i.counter = ctr;
						databases.put(dbname, i);
						counters.put(dbname, ctr);
						i.init(dbname, num, ctr);
					}
					
					log.write("***** Before Insertion *****");
					log.write(dbname.toUpperCase()+" - "+fS[fctr].getStats());
					long start = System.nanoTime();
					test1(i, datafilename);
					long end = System.nanoTime();
					long time = end - start;
					
					log.write("***** After Insertion *****");
					log.write("Time Taken (in nanotime): "+time);
					
					log.write("\t\tNew stats:");
					int temp = fS[fctr].getPagesAllocated();
					log.write("\t\tPage allocated - "+(PCounter.getPagesAllocated() - pagesAllocated));
					log.write("\t\tRead Count - "+(PCounter.getreadCounter() - readCounter));
					log.write("\t\tWrite Count -"+(PCounter.getwriteCounter() - writeCounter));
					log.write("");
					fS[fctr].setNo_of_files((PCounter.get_no_of_files() - no_of_files)+fS[fctr].getNo_of_files());
					fS[fctr].setPagesAllocated((PCounter.getPagesAllocated() - pagesAllocated)+fS[fctr].getPagesAllocated());
					fS[fctr].setPagesDeallocated((PCounter.getPagesDeallocated() - pagesDeallocated)+fS[fctr].getPagesDeallocated());
					fS[fctr].setReadCounter((PCounter.getreadCounter() - readCounter)+fS[fctr].getReadCounter());
					fS[fctr].setWriteCounter((PCounter.getwriteCounter() - writeCounter)+fS[fctr].getWriteCounter());
					log.write(dbname.toUpperCase()+" - "+fS[fctr].getStats());
					log.write(dbname.toUpperCase()+" - "+PCounter.getStats());
					break;
				case 9:
					System.out.println("\t\tPlease choose a database name");
					System.out.println("\t\tAvailable databases are...");
					for (String name: databases.keySet()) 
							System.out.println(name);
					String db_name = GetStuff.getStrChoice();				
					Integer db_ctr = counters.get(db_name);
					i = databases.get(db_name); 
					if (db_ctr == null) {
						throw new Exception ("unknown database");
					}
					if (i == null) {
						throw new Exception ("unknown database");
					}
					i.counter = db_ctr;
					start = System.nanoTime();
					String queryFile = "//home//indrani//Downloads//minjava//DBI_phase2//src//tests//queryfile.txt";
					query newQuery = new query(i, queryFile);
					end = System.nanoTime();
					time = end - start;
					
					log.write("***** After Join *****");
					log.write("Time Taken (in nanotime): "+time);
					log.write("\t\tNew stats:");
					log.write("\t\tPage allocated - "+(PCounter.getPagesAllocated() - pagesAllocated));
					log.write("\t\tRead Count - "+(PCounter.getreadCounter() - readCounter));
					log.write("\t\tWrite Count -"+(PCounter.getwriteCounter() - writeCounter));
					log.write("");
					fS[fctr].setNo_of_files((PCounter.get_no_of_files() - no_of_files)+fS[fctr].getNo_of_files());
					fS[fctr].setPagesAllocated((PCounter.getPagesAllocated() - pagesAllocated)+fS[fctr].getPagesAllocated());
					fS[fctr].setPagesDeallocated((PCounter.getPagesDeallocated() - pagesDeallocated)+fS[fctr].getPagesDeallocated());
					fS[fctr].setReadCounter((PCounter.getreadCounter() - readCounter)+fS[fctr].getReadCounter());
					fS[fctr].setWriteCounter((PCounter.getwriteCounter() - writeCounter)+fS[fctr].getWriteCounter());
					log.write(db_name.toUpperCase()+" - "+fS[fctr].getStats());
					log.write(db_name.toUpperCase()+" - "+PCounter.getStats());
					break;
				case 1:
					System.out.println("Please select the index file to open.");
					System.out.println("\t1. Index on Subject-Predicate-Object ");
					System.out.println("\t2. Index on Predicate-Subject-Object");
					System.out.println("\t3. Index on Subject-Confidence");
					System.out.println("\t4. Index on Predicate-Confidence");
					System.out.println("\t5. Index on Object-Confidence");
					System.out.println("\t6. Index on Confidence");
					int indexDisplay = GetStuff.getIntChoice();
					if((indexDisplay < 1 || indexDisplay > 6) && indexOption == 0){
						System.out.println("No such index exists");
					}else{
						file = new BTreeFile("BTreeIndex_"+getIndexType(indexDisplay));
						BT.printBTree(file.getHeaderPage());
					}
					break;
				case 2:
					System.out.println("Please select the index file to open.");
					System.out.println("\t1. Index on Subject-Predicate-Object ");
					System.out.println("\t2. Index on Predicate-Subject-Object");
					System.out.println("\t3. Index on Subject-Confidence");
					System.out.println("\t4. Index on Predicate-Confidence");
					System.out.println("\t5. Index on Object-Confidence");
					System.out.println("\t6. Index on Confidence");
					int indexDisplay2 = GetStuff.getIntChoice();
					if((indexDisplay2 < 1 || indexDisplay2 > 6) && indexOption == 0){
						System.out.println("No such index exists");
					}else{
						file = new BTreeFile("BTreeIndex_"+getIndexType(indexDisplay2));
						BT.printAllLeafPages(file.getHeaderPage());
					}
					break;
				case 3: 
					System.out.println("\t\tPlease choose a database name");
					System.out.println("\t\tAvailable databases are...");
					for (String name: databases.keySet()) 
							System.out.println("\t\t\t"+name);
							String db = GetStuff.getStrChoice();				
							Integer _ctr = counters.get(db);
							i = databases.get(db); 
							if (_ctr == null) {
								throw new Exception ("unknown database");
							}
							if (i == null) {
								throw new Exception ("unknown database");
							}
							i.counter = _ctr;
							System.out.println("Please provide an order option");
							System.out.println(" 1. Subject-Predicate-Object");
							System.out.println(" 2. Predicate-Subject-Object");
							System.out.println(" 3. Subject-Confidence");
							System.out.println(" 4. Predicate-Confidence");
							System.out.println(" 5. Object-Confidence");
							System.out.println(" 6. Confidence");
							orderOption = GetStuff.getIntChoice();
							System.out.println("Please provide subject filter");
							String subject = GetStuff.getStrChoice();
							System.out.println("Please provide predicate filter");
							String predicate = GetStuff.getStrChoice();
							System.out.println("Please provide object filter");
							String object = GetStuff.getStrChoice();
							System.out.println("Please provide confidence filter");
							float confidence = GetStuff.getFloatChoice();
							System.out.println("How many buffers required?");
							int bufCnt = GetStuff.getIntChoice();
							
							start = System.nanoTime();
							i.querySystem(subject, predicate, object, confidence, getIndexType(orderOption), bufCnt);
							end = System.nanoTime();
							time = end - start;
							
							log.write("***** After Query *****");
							log.write("Time Taken (in nanotime): "+time);
							
							log.write("\t\tNew stats:");
							log.write("\t\tPage allocated - "+(PCounter.getPagesAllocated() - pagesAllocated));
							log.write("\t\tRead Count - "+(PCounter.getreadCounter() - readCounter));
							log.write("\t\tWrite Count -"+(PCounter.getwriteCounter() - writeCounter));
							log.write("");
							fS[fctr].setNo_of_files((PCounter.get_no_of_files() - no_of_files)+fS[fctr].getNo_of_files());
							fS[fctr].setPagesAllocated((PCounter.getPagesAllocated() - pagesAllocated)+fS[fctr].getPagesAllocated());
							fS[fctr].setPagesDeallocated((PCounter.getPagesDeallocated() - pagesDeallocated)+fS[fctr].getPagesDeallocated());
							fS[fctr].setReadCounter((PCounter.getreadCounter() - readCounter)+fS[fctr].getReadCounter());
							fS[fctr].setWriteCounter((PCounter.getwriteCounter() - writeCounter)+fS[fctr].getWriteCounter());
							log.write(db.toUpperCase()+" - "+fS[fctr].getStats());
							log.write(db.toUpperCase()+"Overall - "+PCounter.getStats());
							break;
				case 20: 
					System.out.println("Cleaning up...");
					break;
				case 4:
					System.out.println("Please choose a database name");
					System.out.println("Available databases are...");
					for (String name: databases.keySet()) 
						System.out.println(name);
					db = GetStuff.getStrChoice();				
					_ctr = counters.get(db);
					i = databases.get(db); 
					if (_ctr == null) {
						throw new Exception ("unknown database");
					}
					if (i == null) {
						throw new Exception ("unknown database");
					}
					i.counter = _ctr;
					System.out.println("Please provide subject filter");
					subject = GetStuff.getStrChoice();
					System.out.println("Please provide predicate filter");
					predicate = GetStuff.getStrChoice();
					System.out.println("Please provide object filter");
					object = GetStuff.getStrChoice();
					log.write("***** Before Deletion *****");
					log.write(db.toUpperCase()+" - "+i.getStats().getStats());
					long start2 = System.nanoTime();
					i.deleteTriple(subject, predicate, object);
					long end2 = System.nanoTime();
					long time2 = end2 - start2;
					log.write("***** After Deletion *****");
					log.write("Time Taken (in nanotime): "+time2);
					log.write(db.toUpperCase()+" for particular database - "+i.getStats().getStats());
					log.write(db.toUpperCase()+" for all database - "+PCounter.getStats());
					break;
				case 5:
					System.out.println("Please choose a database name");
					db = GetStuff.getStrChoice();				
					_ctr = counters.get(db);
					i = databases.get(db); 
					if (_ctr == null) {
						throw new Exception ("unknown database");
					}
					if (i == null) {
						throw new Exception ("unknown database");
					}
					i.counter = _ctr;
					System.out.println("Please provide entity filter");
					subject = GetStuff.getStrChoice();
					i.deleteEntity(subject);
					break;
				case 7:
					try{
						Runtime load = Runtime.getRuntime();
						log.flush();
						String fileStr = "//home//indrani//Downloads//minjava//DBI_phase2//src//tests//rdfLogFile0.log";

						load.exec("gedit "+fileStr);
					}catch (Exception e) {
						e.printStackTrace();
					}
					break;
				case 8:
					System.out.println("Available databases are...");
					for (String name: databases.keySet()) 
						System.out.println(name);
					System.out.println("Compares executio of a query using index and without using index");
					System.out.println("Query:: SELECT * FROM RDF WHERE subject = ? ORDER BY subject, predicate, object");
					System.out.println("Please choose a database name");
					db = GetStuff.getStrChoice();									
					_ctr = counters.get(db);
					i = databases.get(db); 
					if (_ctr == null) {
						throw new Exception ("unknown database");
					}
					if (i == null) {
						throw new Exception ("unknown database");
					}
					i.counter = _ctr;
					System.out.println("Please provide subject filter");
					subject = GetStuff.getStrChoice();
					System.out.println("How many buffers required?");
					int buf_size = GetStuff.getIntChoice();
					System.out.println("Without indices");
					i.querySystemNaive(subject, null, null, (float) 0.0, RdbIndexType.SPO, buf_size);
					System.out.println("With indices");
					i.querySystem(subject, null, null, (float) 0.0, RdbIndexType.SPO, buf_size);
					break;
				default:
					System.out.println("Operation not supported..");
					break;
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}

	private RdbIndexType getIndexType(int indexOption) throws Exception{
		switch(indexOption){
		case 1: return RdbIndexType.SPO;
		case 2: return RdbIndexType.PSO;
		case 3: return RdbIndexType.SC;
		case 4: return RdbIndexType.PC;
		case 5: return RdbIndexType.OC;
		case 6: return RdbIndexType.C;
		case 11: return RdbIndexType.E;
		case 12: return RdbIndexType.P;
		case 7: return RdbIndexType.PO;
		case 8: return RdbIndexType.SO;
		case 99: return RdbIndexType.ALL;
		default: throw new Exception("INVALID INDEX OPTION: No such index is supported");
		}
	}

	private void test1(Interface3 i, String filename) throws JoinsException, IndexException, InvalidTupleSizeException, InvalidTypeException, PageNotReadException, PredEvalException, SortException, LowMemException, UnknowAttrType, Exception{
		String[] dataval= null;
		String[] dataval2= null;
		try{
			String datafilename="//home//indrani//Downloads//minjava//DBI_phase2//src//tests//"+filename;
//			String datafilename="//home//smriti//workspace//rdfDBI//src//tests//"+filename;
			FileReader f=new FileReader(datafilename);

			BufferedReader in = new BufferedReader(f);
			String str;
			while ((str = in.readLine()) != null) {
				try{
					dataval=str.split(":");	
					dataval2=dataval[3].split("\\s+");
					String confidence=dataval2[1];
					i.insertTriple(dataval[1].trim(),dataval[2].trim(),dataval2[0].trim(),Float.parseFloat(confidence),RdbIndexType.ALL);
				}
				catch(Exception e)
				{continue;}
			}
			rdfDB db = new rdfDB(i, 1);
//			i.unpinAllIndexFiles();
//			SystemDefs.JavabaseBM.flushAllPages();
			/*System.out.println("\t\t\t******Insertion statistics*******\t\t\t");
			System.out.println("\t\t\t[Total distinct subject: "+db.getSubjectCnt()+"]\t");
			System.out.println("\t\t\t[Total distinct object"+db.getObjectCnt()+"]\t");
			*/System.out.println("\n\t\t\t[Total entities: "+db.getEntityCnt()+"]\t");
			System.out.println("\t\t\t[Total predicate: "+db.getPredicateCnt()+"]\t");
			System.out.println("\t\t\t[Total number of triples in the file: "+db.getTripleCnt()+"]\t\n\n");
			in.close();
		} catch (IOException e) {
			throw new Exception("ERROR OPENING THE FILE: "+filename+". Please verify the filename");
		}
	}
	/**
	 * @param args
	 * @throws Exception 
	 * @throws PinPageException 
	 * @throws GetFileEntryException 
	 */
	public static void main(String[] args) throws GetFileEntryException, PinPageException, Exception {
		// TODO Auto-generated method stub
		runTest test = new runTest();
		test.runAllTests();
	}

}
